#include <sys/types.h>
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

#include <stdatomic.h>
#include "list.h"

#include "somb.h"
#include "somb_common.h"
#include "somb_lib.h"
#include "somb_manager.h"
#include "somb_log.h"
#include "somb_message.h"
#include "somb_sock.h"
#include "message_queue.h"
#include "somb_work.h"
#include "somb_conf.h"


typedef struct somb_user_if_service
{
    uint32_t ServiceId;
    uint32_t ServiceType;
    void *ServicePriv;
    struct somb_user_if_service *prev; 
    struct somb_user_if_service *next; 
}ST_SOMB_USER_IF_SERVICE;


ST_SOMB_DAEMON_CONF gstSombConf= {0};

int32_t i32SOMB_SubNs_Init(uint32_t *pSubNsId)
{
    int32_t ret32 = SOMB_OK;
    char conf_file[256];
    memset(conf_file,0,sizeof(conf_file));
    if(access(SOMB_DAEMON_CONFIG,F_OK) !=0)
    {
        fprintf(stderr,"somb :pid(%d) cann't access somb conf file\n",getpid());
        return -1;
    }

    if(NULL == pSubNsId)
    {
        fprintf(stderr,"somb :pid(%d) SubNs init parameter failed\n",getpid());
        return -1;
    }

    int fd = open(SOMB_DAEMON_CONFIG,O_RDONLY);
    if(-1 == fd)
    {
        fprintf(stderr,"somb :pid(%d) cann't read somb conf file\n",getpid());
        return -2;
    }
    
    read(fd,conf_file,sizeof(conf_file));

    close(fd);

    if(0 != somb_config_file_parser(conf_file,&gstSombConf))
    {
        fprintf(stderr,"somb : the config file of somb[%s] has some wrong configurations\n",conf_file);
        return -1;
    }

    st_somb_logfile_config stlogfileconf;
    sprintf(stlogfileconf.log_path,"%s",gstSombConf.log_path);
    stlogfileconf.log_level = gstSombConf.log_level;
    stlogfileconf.log_file_size = gstSombConf.log_file_size;
    stlogfileconf.log_file_num = gstSombConf.log_file_num;

    if( 0 != somb_log_init(&stlogfileconf))
    {
        printf("somb: log init failed,path=%s level=%d\n",gstSombConf.log_path,gstSombConf.log_level);
        return -1;
    }

    ret32 = i32SOMB_Manager_SubNs_Init(pSubNsId);
    return ret32;
}

void ** vSOMB_Service_Instance_New()
{
    ST_SOMB_USER_IF_SERVICE  **head=malloc(sizeof(ST_SOMB_USER_IF_SERVICE*));
    if(NULL == head)
    {
        SOMB_LOG_ERR("somb user:pid(%d) malloc for method instance failed",getpid());
        return NULL;
    }

    *head = NULL;
    //memset(head,0,sizeof(ST_SOMB_USER_IF_SERVICE*));

    //printf("new Instance=%p\n",head);
    return (void **)head;
}

int32_t i32SOMB_Service_Add(void **Instance,uint32_t ServiceId,E_SOMB_SVC_TYPE ServiceType,void *pfFunc)
{

    if((NULL == Instance))
    {
        SOMB_LOG_ERR("somb user:pid(%d) add method , instance is NULL ",getpid());
        return SOMB_PARAM_ERR;
    }


    //SOMB_LOG_DEBUG("somb user:pid(%d) malloc for method user if size(%d) ",getpid(),sizeof(ST_SOMB_USER_IF_SERVICE));
    ST_SOMB_USER_IF_SERVICE *newItem = malloc(sizeof(ST_SOMB_USER_IF_SERVICE));
    if(NULL == newItem)
    {
        SOMB_LOG_ERR("somb user:pid(%d) malloc for method ServiceId(0x%08x) failed",getpid(),ServiceId);
        return SOMB_FAIL;
    }
    //printf("new item=%p\n",newItem);

    newItem->ServiceId = ServiceId;
    newItem->ServiceType = ServiceType;
    newItem->ServicePriv = pfFunc;
 

    DL_APPEND(*(ST_SOMB_USER_IF_SERVICE**)Instance,newItem);

    return SOMB_OK;
}

int32_t i32SOMB_Service_Instance_Deploy(void **Instance)
{
    int32_t ret;
    if((NULL == Instance))
    {
        SOMB_LOG_ERR("somb user:pid(%d) method deploy failed , instance is NULL ",getpid());
        return SOMB_PARAM_ERR;
    }


    uint32_t ServiceSize = 0;
    DL_LENGTH((ST_SOMB_USER_IF_SERVICE*)(*Instance),ServiceSize);
    //ServiceSize--;
    if(0 == ServiceSize)
    {
        SOMB_LOG_ERR("somb user:pid(%d) method deploy failed , service size is 0",getpid());
        return SOMB_PARAM_ERR;
    }

    struct somb_mngr_reg_serviceitem *pui32ServiceList = malloc(sizeof(struct somb_mngr_reg_serviceitem)*ServiceSize);
    if((NULL == pui32ServiceList))
    {
        SOMB_LOG_ERR("somb user:pid(%d) method deploy ,malloc service list failed",getpid());
        return SOMB_FAIL;
    }

    struct somb_local_sub_ns *pstLocalSubNs = pstSOMB_GetLocalSubNs();
    if(NULL == pstLocalSubNs)
    {
        SOMB_LOG_ERR("somb user:pid(%d) method deploy ,get local Sub ns failed",getpid());
        return SOMB_FAIL;
    }

    SOMB_LOG_DEBUG("somb user:subns(%s) pid(%d) method deploy ,service len=%d",pstLocalSubNs->localexename,pstLocalSubNs->localpid,ServiceSize);

    struct somb_mngr_sub_ns *pstSubNs;
    pstSubNs = pstSOMB_Manager_Find_SubNs(pstLocalSubNs->sub_ns_id);

    uint32_t loop = 0;
    ST_SOMB_USER_IF_SERVICE *item=NULL,*tmp=NULL;
    DL_FOREACH_SAFE(*(ST_SOMB_USER_IF_SERVICE**)Instance, item, tmp)
    {
        pui32ServiceList[loop].ServiceId = item->ServiceId;
        pui32ServiceList[loop].ServiceType = item->ServiceType;

        if(NULL == pstSOMB_Manager_SaveService(pui32ServiceList[loop].ServiceId,item->ServiceType,item->ServicePriv, pstSubNs))
        {
            SOMB_LOG_ERR("somb user:subns(%s) pid(%d) method deploy service(%08x)",pstLocalSubNs->localexename,pstLocalSubNs->localpid,item->ServiceId);
        }
        loop++;
        DL_DELETE((*(ST_SOMB_USER_IF_SERVICE**)Instance),item);
        free(item);
    }

    ret = i32SOMB_Manager_RegisterService_Daemon(pui32ServiceList,ServiceSize);
    if(SOMB_OK != ret)
    {
        SOMB_LOG_ERR("somb msg:pid(%d) register method to daemon failed",getpid());
    }

    free(pui32ServiceList);

    return ret;
}

int32_t i32SOMB_Service_Instance_Destroy(void **Instance)
{
    //printf("free instance=%p\n",Instance);
    free(Instance);
    return SOMB_OK;
}

int32_t i32somb_send_message_raw(struct somb_local_sub_ns *pstLocalSubNs,struct somb_mngr_sub_ns *pstDestSubNs,uint8_t *header,void *InData, uint32_t InDataLen )
{
    if(NULL == pstDestSubNs) 
    {
        SOMB_LOG_ERR("somb msg:subns(%s) pid(%d) send mesage raw  pstDestSubNs is NULL",pstLocalSubNs->localexename,getpid());
        return SOMB_PARAM_ERR;
    }

    if(pstDestSubNs->SubNsStatus != SOMB_SUBNS_STATUS_ONLINE)
    {
        
        SOMB_LOG_ERR("somb msg:subns(%s) pid(%d) ,peer(%s)-(%d) is not online",pstLocalSubNs->localexename,getpid(),pstDestSubNs->sub_ns_name,pstDestSubNs->sub_ns_id);
        if(SOMB_OK == somb_manager_connect_remote_subns(pstDestSubNs))
        {
            SOMB_LOG_WARN("somb msg:subns(%s) pid(%d) try to  connect to SubNs(%s)-(%d) SUCCESS",pstLocalSubNs->localexename,getpid(),pstDestSubNs->sub_ns_name,pstDestSubNs->sub_ns_id);

        }
        else
        {
            SOMB_LOG_ERR("somb msg:subns(%s) pid(%d) try to  connect to SubNs(%s)-(%d) NG",pstLocalSubNs->localexename,getpid(),pstDestSubNs->sub_ns_name,pstDestSubNs->sub_ns_id);
            return SOMB_SERVICEID_INVALID;
        }
    }
    struct iovec iov[2];
    struct msghdr msg;
    iov[0].iov_base = header;
    iov[0].iov_len = SOMB_MESSAGE_HEADER_SIZE;
    iov[1].iov_base = InData;
    iov[1].iov_len = InDataLen;

    // Set up the msghdr structure
    memset(&msg, 0, sizeof(msg));
    msg.msg_iov = iov;
    if((NULL == InData) || (0 == InDataLen) ||(0xFDFEFAFD == InDataLen))
        msg.msg_iovlen = 1;
    else
        msg.msg_iovlen = 2;

    int32_t ret;
    ret = sendmsg(pstDestSubNs->skfd, &msg, MSG_NOSIGNAL);

    if(-1 == ret)
    {
        if(SOMB_OK != somb_manager_connect_remote_subns(pstDestSubNs))
        {
            SOMB_LOG_ERR("somb sock:(%s) send to Dest SubNs(%s) return(%d) failed,errno=%s",pstLocalSubNs->localexename,pstDestSubNs->sub_ns_addr,ret,strerror(errno));
            pstDestSubNs->SubNsStatus = SOMB_SUBNS_STATUS_OFFLINE;
            ret = SOMB_FAIL;
        }
        else
        {
            ret = sendmsg(pstDestSubNs->skfd, &msg, MSG_NOSIGNAL);
            if(-1 == ret)
            {
                SOMB_LOG_ERR("somb sock:(%s) send to Dest SubNs(%s) return(%d) failed,errno=%s",pstLocalSubNs->localexename,pstDestSubNs->sub_ns_addr,ret,strerror(errno));
                ret = SOMB_FAIL;
            }
            else
            {
                SOMB_LOG_DEBUG("somb sock:(%s) send to Dest SubNs(%s) return(%d) ",pstLocalSubNs->localexename,pstDestSubNs->sub_ns_addr,ret);
                ret =  SOMB_OK;
            }

        }
    }
    else
    {
        SOMB_LOG_DEBUG("somb sock:(%s) send to Dest SubNs(%s) return(%d) ",pstLocalSubNs->localexename,pstDestSubNs->sub_ns_addr,ret);
        ret =  SOMB_OK;
    }

    return ret;

}
int32_t i32SOMB_Method_SetRequest(uint32_t ServiceId,void *InData,uint32_t InDataLen)
{
    int32_t ret;
    struct somb_local_sub_ns *pstLocalSubNs = pstSOMB_GetLocalSubNs();
    if(NULL == pstLocalSubNs)
    {
        SOMB_LOG_ERR("somb msg:pid(%d) send method set request(%08x), get local sub ns failed",getpid(),ServiceId);
        return SOMB_FAIL;
    }

    ST_SOMB_LIB_SERVICE_LIST * pstLibServiceList = pstSOMBManagerGetServiceInfo(ServiceId);
    if(NULL == pstLibServiceList)
    {
        SOMB_LOG_ERR("somb msg:subns(%s) pid(%d) send method set request(%08x), get Service list failed",pstLocalSubNs->localexename,getpid(),ServiceId);
        return SOMB_FAIL;
    }

    if(pstLibServiceList->pstSubNs == NULL)
    {
        SOMB_LOG_ERR("somb msg:subns(%s) pid(%d) send method set Request(%08x),but its subns not reg",pstLocalSubNs->localexename,getpid(),ServiceId);
        return SOMB_SERVICEID_INVALID;
    }

    if(pstLibServiceList->status !=SOMB_SERVICE_STATUS_READY )
    {
        SOMB_LOG_ERR("somb msg:subns(%s) pid(%d) send method set Request(%08x),but status is (%d)",pstLocalSubNs->localexename,getpid(),ServiceId,pstLibServiceList->status);
        return SOMB_SERVICEID_INVALID;
    }

    atomic_fetch_add(&(pstLibServiceList->ServiceCount),1);
    pthread_mutex_lock(&(pstLibServiceList->pstSubNs->mutex_lock));

    uint8_t header[SOMB_MESSAGE_HEADER_SIZE]={0};
    uint32_t tmpsize=0;

    //uint8_t header[SOMB_MESSAGE_HEADER_SIZE];
    uint8_t MsgSeqId = atomic_fetch_add(&(pstLibServiceList->pstSubNs->MsgSeqId),1);
    if((NULL == InData) || (0 == InDataLen))
    {
        tmpsize = 0;
        SOMB_MESSAGE_HEADER_INIT(header,pstLocalSubNs->sub_ns_id,MsgSeqId,ServiceId,SOMB_MSG_TYPE_METHOD_SETREQUEST,0);
    }
    else
    {
        tmpsize = InDataLen;
        SOMB_MESSAGE_HEADER_INIT(header,pstLocalSubNs->sub_ns_id,MsgSeqId,ServiceId,SOMB_MSG_TYPE_METHOD_SETREQUEST,InDataLen);
    }

    ret = i32somb_send_message_raw(pstLocalSubNs,pstLibServiceList->pstSubNs,header,InData,tmpsize);
    if(SOMB_OK != ret)
    {
        atomic_fetch_add(&(pstLibServiceList->ServiceFailCount),1);
    }

    pthread_mutex_unlock(&(pstLibServiceList->pstSubNs->mutex_lock));
    return ret;
}

int32_t i32SOMB_Method_Request_Sync(uint32_t ServiceId, void *MthReqData, uint32_t MthReqDataLen,void *MthRespData, uint32_t *MthRespDataLen,uint32_t timeout_ms)
{
    int32_t ret;
    struct somb_local_sub_ns *pstLocalSubNs = pstSOMB_GetLocalSubNs();
    if(NULL == pstLocalSubNs)
    {
        SOMB_LOG_ERR("somb msg:pid(%d) send method Request Sync(%08x), get local sub ns failed",getpid(),ServiceId);
        return SOMB_FAIL;
    }

    ST_SOMB_LIB_SERVICE_LIST * pstLibServiceList = pstSOMBManagerGetServiceInfo(ServiceId);
    if(NULL == pstLibServiceList)
    {
        SOMB_LOG_ERR("somb msg:subns(%s) pid(%d) send method Request Sync(%08x), get Service list failed",pstLocalSubNs->localexename,getpid(),ServiceId);
        return SOMB_SERVICEID_INVALID;
    }

    if(pstLibServiceList->pstSubNs == NULL)
    {
        SOMB_LOG_ERR("somb msg:subns(%s) pid(%d) send method Request Sync(%08x),but its subns not reg",pstLocalSubNs->localexename,getpid(),ServiceId);
        return SOMB_SERVICEID_INVALID;
    }

    if(pstLibServiceList->status != SOMB_SERVICE_STATUS_READY )
    {
        SOMB_LOG_ERR("somb msg:subns(%s) pid(%d) send method Request Sync(%08x),but status is (%d)",pstLocalSubNs->localexename,getpid(),ServiceId,pstLibServiceList->status);
        return SOMB_SERVICEID_INVALID;
    }


    atomic_fetch_add(&(pstLibServiceList->ServiceCount),1);

    pthread_mutex_lock(&(pstLibServiceList->pstSubNs->mutex_lock));

    uint8_t MsgSeqId = atomic_fetch_add(&(pstLibServiceList->pstSubNs->MsgSeqId),1);

    /*add expected response info to resp_data_head*/
    struct somb_mngr_sub_ns_resp_data expected_resp_data;
    bzero(&expected_resp_data,sizeof(struct somb_mngr_sub_ns_resp_data));
    expected_resp_data.ServiceId = ServiceId;
    expected_resp_data.MsgSeqId = MsgSeqId;
    expected_resp_data.data = NULL;
    expected_resp_data.bComplete = false;
    DL_PREPEND(pstLibServiceList->pstSubNs->resp_data_head,&expected_resp_data);

    uint8_t header[SOMB_MESSAGE_HEADER_SIZE]={0};
    uint32_t tmpsize=0;
    if((NULL == MthReqData) || (0 == MthReqDataLen))
    {
        tmpsize = 0;
        SOMB_MESSAGE_HEADER_INIT(header,pstLocalSubNs->sub_ns_id,MsgSeqId,ServiceId,SOMB_MSG_TYPE_METHOD_REQUEST_SYNC,0);

    }
    else{
        tmpsize = MthReqDataLen;
        SOMB_MESSAGE_HEADER_INIT(header,pstLocalSubNs->sub_ns_id,MsgSeqId,ServiceId,SOMB_MSG_TYPE_METHOD_REQUEST_SYNC,MthReqDataLen);
    }
    ret = i32somb_send_message_raw(pstLocalSubNs,pstLibServiceList->pstSubNs,header,MthReqData,tmpsize);
    if(0 != ret)
    {
        atomic_fetch_add(&(pstLibServiceList->ServiceFailCount),1);
        SOMB_LOG_ERR("somb msg:pid(%d) send method Request Sync(%08x) failed",getpid(),ServiceId);
        DL_DELETE(pstLibServiceList->pstSubNs->resp_data_head,&expected_resp_data);
        pthread_mutex_unlock(&(pstLibServiceList->pstSubNs->mutex_lock));
        return ret;
    }


#if 0
    uint8_t Empty=0;
    DL_EMPTY(pstLibServiceList->pstSubNs->resp_data_head,Empty);
#endif

    struct timespec abstime;
    clock_gettime(CLOCK_MONOTONIC, &abstime);
    uint64_t tmp_nsec=  (uint64_t)(abstime.tv_nsec) + timeout_ms*1E6;
    abstime.tv_sec += tmp_nsec/1000000000;
    abstime.tv_nsec = tmp_nsec%1000000000;

    //bool bGotRespSync=false;
    do{
        SOMB_LOG_DEBUG("somb msg:subns(%s) pid(%d) wait for sync resp(%08x) MsgSeqId(%d)....",pstLocalSubNs->localexename,pstLocalSubNs->localpid,ServiceId,MsgSeqId);
        ret =  pthread_cond_timedwait(&(pstLibServiceList->pstSubNs->cond), &(pstLibServiceList->pstSubNs->mutex_lock),&abstime);
        if(ret != 0)
        {
            if((EINVAL == ret) || (ETIMEDOUT ==  ret))
            {
                SOMB_LOG_ERR("somb msg:subns(%s) pid(%d) timedwait for resp(%08x) MsgSeqId(%d)failed,ret=%d",pstLocalSubNs->localexename,getpid(),ServiceId,MsgSeqId,ret);
                ret = SOMB_TIMEOUT;
                break;
            }
        
            if ((EINTR == errno) || (EAGAIN == errno))
            {
        
                SOMB_LOG_ERR("somb msg:subns(%s) pid(%d) timedwait for resp(%08x) MsgSeqId(%d)failed,errno=%s,try again",pstLocalSubNs->localexename,getpid(),ServiceId,MsgSeqId,strerror(errno));
                continue;
            }
            else
            {
                SOMB_LOG_ERR("somb msg:subns(%s) pid(%d) timedwait for resp(%08x) MsgSeqId(%d)failed,errno=%s",pstLocalSubNs->localexename,getpid(),ServiceId,MsgSeqId,strerror(errno));
                ret = SOMB_FAIL;
                break;
            }
        
        }
        else
        {
            if(expected_resp_data.bComplete)
            {
                ret = SOMB_OK;
                break;
            }
            else {
                //continue to wait
            }
        }

#if 0
        struct somb_mngr_sub_ns_resp_data *item,*tmp;
        DL_FOREACH_SAFE(pstLibServiceList->pstSubNs->resp_data_head,item,tmp)
        {
            //SOMB_LOG_DEBUG("somb msg:subns(%s) pid(%d) search ServiceId(%08x) SeqId(%d) ",pstLocalSubNs->localexename,getpid(),item->ServiceId,item->MsgSeqId);
            if((item->ServiceId == ServiceId)&&(SeqId == item->MsgSeqId))
            {
                bGotRespSync=true;
                break;
            }
        }

        if(bGotRespSync)
        {
            break;
        }
#endif
    }while(1);

    
    if(SOMB_OK != ret)
    {
        //SOMB_LOG_ERR("somb msg:subns(%s) pid(%d) wait for sync resp(%08x) MsgSeqId(%d) failed",pstLocalSubNs->localexename,getpid(),ServiceId,MsgSeqId);
        DL_DELETE(pstLibServiceList->pstSubNs->resp_data_head,&expected_resp_data);
        pthread_mutex_unlock(&(pstLibServiceList->pstSubNs->mutex_lock));
        return ret;
    }

    SOMB_LOG_DEBUG("somb msg:subns(%s) pid(%d) wait for sync resp(%08x) MsgSeqId(%d)success",pstLocalSubNs->localexename,getpid(),ServiceId,MsgSeqId);

/*
        if((expected_resp_data.data != NULL) && \
            (expected_resp_data.data_len > 0) &&\
            (expected_resp_data.data_len != 0xFDFEFAFD))
*/
    {
        if((NULL != MthRespData) && (NULL != MthRespDataLen))
        {
            if(*MthRespDataLen < expected_resp_data.data_len)
            {
                SOMB_LOG_ERR("somb msg:subns(%s) pid(%d) wait for resp(%08x) ok,but MthReqDataLen is too short ",pstLocalSubNs->localexename,getpid(),ServiceId);
                ret = SOMB_LENGTH_ERR;
            }
            else
            {
                if((expected_resp_data.data != NULL) &&(expected_resp_data.data_len > 0))
                    memcpy(MthRespData,expected_resp_data.data,expected_resp_data.data_len);
                else
                {
                    SOMB_LOG_DEBUG("somb msg:subns(%s) pid(%d) wait for resp(%08x) ok,but expected_resp data is (%p %d)",\
                                 pstLocalSubNs->localexename,getpid(),ServiceId,expected_resp_data.data,expected_resp_data.data_len);
                }
            }

        }
    }

    if(NULL != MthRespDataLen)
        *MthRespDataLen = expected_resp_data.data_len;

    if(NULL != expected_resp_data.data)
        free(expected_resp_data.data);

    //delete from resp data list 
    DL_DELETE(pstLibServiceList->pstSubNs->resp_data_head,&expected_resp_data);
    //free(item);

    pthread_mutex_unlock(&(pstLibServiceList->pstSubNs->mutex_lock));
    return ret;
}

int32_t i32SOMB_Method_Request_Async(uint32_t ServiceId, void *MthReqData, uint32_t MthReqDataLen,PF_SOMB_METHOD_ASYNC_CB pfMthAsyncFunc)
{
    int32_t ret;
    struct somb_local_sub_ns *pstLocalSubNs = pstSOMB_GetLocalSubNs();
    if(NULL == pstLocalSubNs)
    {
        SOMB_LOG_ERR("somb msg:pid(%d) send method Request Async(%08x), get local sub ns failed",getpid(),ServiceId);
        return SOMB_FAIL;
    }

    ST_SOMB_LIB_SERVICE_LIST * pstLibServiceList = pstSOMBManagerGetServiceInfo(ServiceId);
    if(NULL == pstLibServiceList)
    {
        SOMB_LOG_ERR("somb msg:(%s) pid(%d) send method Request Async(%08x), get Service list failed",pstLocalSubNs->localexename,getpid(),ServiceId);
        return SOMB_FAIL;
    }

    if(pstLibServiceList->pstSubNs == NULL)
    {
        SOMB_LOG_ERR("somb msg:subns(%s) pid(%d) send method Request Async(%08x),but its subns not reg",pstLocalSubNs->localexename,getpid(),ServiceId);
        return SOMB_SERVICEID_INVALID;
    }

    if(pstLibServiceList->status !=SOMB_SERVICE_STATUS_READY )
    {
        SOMB_LOG_ERR("somb msg:subns(%s) pid(%d) send method Request Async(%08x),but status is (%d)",pstLocalSubNs->localexename,getpid(),ServiceId,pstLibServiceList->status);
        return SOMB_SERVICEID_INVALID;
    }

    vSOMB_Manager_Save_Method_AsyncCB(ServiceId,pfMthAsyncFunc);

    atomic_fetch_add(&(pstLibServiceList->ServiceCount),1);

    pthread_mutex_lock(&(pstLibServiceList->pstSubNs->mutex_lock));
    uint8_t MsgSeqId = atomic_fetch_add(&(pstLibServiceList->pstSubNs->MsgSeqId),1);

    uint8_t header[SOMB_MESSAGE_HEADER_SIZE]={0};
    uint32_t tmpsize=0;
    if((NULL == MthReqData) || (0 == MthReqDataLen))
    {
        tmpsize = 0;
        SOMB_MESSAGE_HEADER_INIT(header,pstLocalSubNs->sub_ns_id,MsgSeqId,ServiceId,SOMB_MSG_TYPE_METHOD_REQUEST_ASYNC,0);
    }
    else{
        tmpsize = MthReqDataLen;
        SOMB_MESSAGE_HEADER_INIT(header,pstLocalSubNs->sub_ns_id,MsgSeqId,ServiceId,SOMB_MSG_TYPE_METHOD_REQUEST_ASYNC,MthReqDataLen);
    }
    ret = i32somb_send_message_raw(pstLocalSubNs,pstLibServiceList->pstSubNs,header,MthReqData,tmpsize);
    if(0 != ret)
    {
        atomic_fetch_add(&(pstLibServiceList->ServiceFailCount),1);
        SOMB_LOG_ERR("somb msg:(%s) pid(%d) send method Request Async(%08x) failed",pstLocalSubNs->localexename,getpid(),ServiceId);
        pthread_mutex_unlock(&(pstLibServiceList->pstSubNs->mutex_lock));
        return ret;
    }
    pthread_mutex_unlock(&(pstLibServiceList->pstSubNs->mutex_lock));
    return ret;

}

int32_t i32SOMB_Method_Complete(uint32_t handle,uint32_t ServiceId,void* MthRespData,uint32_t MthRespDataLen)
{
    int32_t ret;
    struct somb_local_sub_ns *pstLocalSubNs = pstSOMB_GetLocalSubNs();
    if(NULL == pstLocalSubNs)
    {
        SOMB_LOG_ERR("somb msg:pid(%d) send method set request(%08x), get local sub ns failed",getpid(),ServiceId);
        return SOMB_FAIL;
    }


    uint8_t MsgTypeReply ;
    uint8_t MsgType = (handle&0xFF000000)>>24;
    uint8_t SeqId= (handle&0x00FF0000)>>16;
    uint32_t sub_ns_id= handle&0x0000FFFF;
    if(MsgType == SOMB_MSG_TYPE_METHOD_REQUEST_SYNC)
    {
        MsgTypeReply = SOMB_MSG_TYPE_METHOD_RESPONSE_SYNC;
    }
    else if(MsgType == SOMB_MSG_TYPE_METHOD_REQUEST_ASYNC)
    {
        MsgTypeReply = SOMB_MSG_TYPE_METHOD_RESPONSE_ASYNC;
    }
    else
    {
        SOMB_LOG_ERR("somb msg:subns(%s) pid(%d) unspport ServiceId(%08x) msgtype=%d",pstLocalSubNs->localexename,getpid(),ServiceId,MsgType);
        return SOMB_FAIL;
    }

    struct somb_mngr_sub_ns *pstDestSubNs = pstSOMB_GetSubNsById(sub_ns_id);
    if(NULL == pstDestSubNs)
    {
        SOMB_LOG_ERR("somb msg:subns(%s) pid(%d) ServiceId(%08x) MsgType(%d) get sub ns id(%d) NULL",pstLocalSubNs->localexename,getpid(),ServiceId,MsgType,sub_ns_id);
        return SOMB_FAIL;
    }
    
    ST_SOMB_LIB_SERVICE_LIST * pstLibServiceList = pstSOMBManagerGetServiceInfo(ServiceId);
    if(NULL == pstLibServiceList)
    {
        SOMB_LOG_ERR("somb msg:subns(%s) pid(%d) ServiceId(%08x), get Service list failed",pstLocalSubNs->localexename,getpid(),ServiceId);
        return SOMB_FAIL;
    }


    pthread_mutex_lock(&(pstDestSubNs->mutex_lock));
    uint8_t header[SOMB_MESSAGE_HEADER_SIZE];
    uint32_t bodysize=0;
    if((NULL == MthRespData) || (0 == MthRespDataLen ))
    {
        bodysize = 0;
        SOMB_MESSAGE_HEADER_INIT(header,pstLocalSubNs->sub_ns_id,SeqId,ServiceId,MsgTypeReply,0);
        
    }
    else
    {
        SOMB_MESSAGE_HEADER_INIT(header,pstLocalSubNs->sub_ns_id,SeqId,ServiceId,MsgTypeReply,MthRespDataLen);
        bodysize = MthRespDataLen;
    }
    ret = i32somb_send_message_raw(pstLocalSubNs,pstDestSubNs,header,MthRespData,bodysize);
    if(SOMB_OK != ret)
    {
        SOMB_LOG_ERR("somb msg:subns(%s) pid(%d) ServiceId(%08x), MsgType(%d) SeqId(%d) SubNsId(%d) Complete failed",pstLocalSubNs->localexename,getpid(),ServiceId,MsgType,SeqId,sub_ns_id);
    }

    pthread_mutex_unlock(&(pstDestSubNs->mutex_lock));

    return ret;
}


#if 1
int32_t i32SOMB_Msg_Resp_Sync_Complete(uint32_t ServiceId,uint32_t MsgSeqId,void **data,uint32_t data_len)
{
    struct somb_local_sub_ns *pstLocalSubNs = pstSOMB_GetLocalSubNs();
    if(NULL == pstLocalSubNs)
    {
        SOMB_LOG_ERR("somb msg:pid(%d) send method set request(%08x), get local sub ns failed",getpid(),ServiceId);
        return SOMB_FAIL;
    }

    ST_SOMB_LIB_SERVICE_LIST * pstLibServiceList = pstSOMBManagerCheckServiceInfo(ServiceId);
    if(NULL == pstLibServiceList)
    {
        SOMB_LOG_ERR("somb msg:subns(%s) pid(%d) resp sync ServiceId(%08x), get Service list failed",pstLocalSubNs->localexename,getpid(),ServiceId);
        return SOMB_FAIL;
    }

    pthread_mutex_lock(&(pstLibServiceList->pstSubNs->mutex_lock)); 
    bool bGotRespSync=false;
    struct somb_mngr_sub_ns_resp_data *item=NULL,*tmp=NULL;

    DL_FOREACH_SAFE(pstLibServiceList->pstSubNs->resp_data_head,item,tmp)
    {
        //SOMB_LOG_DEBUG("somb msg:subns(%s) pid(%d) search ServiceId(%08x) SeqId(%d) ",pstLocalSubNs->localexename,getpid(),item->ServiceId,item->MsgSeqId);
        if((item->ServiceId == ServiceId)&&(MsgSeqId == item->MsgSeqId))
        {
            bGotRespSync=true;
            break;
        }
    }
    //if(bGotRespSync&&(NULL != item)&&(NULL == item->data))
    if(bGotRespSync)
    {
        item->data_len = data_len;

        if((data_len != 0xFDFEFAFD) && (0 != data_len))
        {
            item->data = *data;
        }
        else
        {
            item->data = NULL; //this should not be acceessed
        }

        item->bComplete = true;

        pthread_cond_broadcast(&(pstLibServiceList->pstSubNs->cond));
    }
    else
    {
        SOMB_LOG_ERR("somb msg:subns(%s) pid(%d) get resp sync of ServiceId(%08x) MsgSeqId(%d), but bGotRespSync(%d) item=%p itemdata=%p",pstLocalSubNs->localexename,getpid(),ServiceId,MsgSeqId,bGotRespSync,item,item?item->data:NULL);
        if(*data)
        {
            free(*data);
        }
    }

    pthread_mutex_unlock(&(pstLibServiceList->pstSubNs->mutex_lock)); 

    return SOMB_OK;
}
#else
int32_t i32SOMB_Msg_Resp_Sync_Complete(struct somb_mngr_sub_ns_resp_data *msgitem)
{
    if(NULL == msgitem)
    {
        SOMB_LOG_ERR("somb msg:pid(%d) resp sync complete  paramter failed",getpid());
        return SOMB_FAIL;
    }

    struct somb_local_sub_ns *pstLocalSubNs = pstSOMB_GetLocalSubNs();
    if(NULL == pstLocalSubNs)
    {
        SOMB_LOG_ERR("somb msg:pid(%d) method resp sync ServiceId(%08x), get local sub ns failed",getpid(),msgitem->ServiceId);
        return SOMB_FAIL;
    }

    ST_SOMB_LIB_SERVICE_LIST * pstLibServiceList = pstSOMBManagerGetServiceInfo(msgitem->ServiceId);
    if(NULL == pstLibServiceList)
    {
        SOMB_LOG_ERR("somb msg:subns(%s) pid(%d) resp sync ServiceId(%08x), get Service list failed",pstLocalSubNs->localexename,getpid(),msgitem->ServiceId);
        return SOMB_FAIL;
    }

    pthread_mutex_lock(&(pstLibServiceList->pstSubNs->mutex_lock)); 
    uint32_t length;
    
    DL_PREPEND(pstLibServiceList->pstSubNs->resp_data_head,msgitem);

    pthread_cond_broadcast(&(pstLibServiceList->pstSubNs->cond));
    pthread_mutex_unlock(&(pstLibServiceList->pstSubNs->mutex_lock)); 
}
#endif

int32_t i32SOMB_ServiceListener_Add(ST_SOMB_SERVICE_LISTEN_INFO ListenList[],uint32_t ListLength)
{
    int32_t ret;

    struct somb_local_sub_ns *pstLocalSubNs = pstSOMB_GetLocalSubNs();
    if(NULL == pstLocalSubNs)
    {
        SOMB_LOG_ERR("somb user:pid(%d) event listener deploy ,get local Sub ns failed",getpid());
        return SOMB_FAIL;
    }

    SOMB_LOG_DEBUG("somb user:subns(%s) pid(%d) event listener deploy ,service len=%d",pstLocalSubNs->localexename,pstLocalSubNs->localpid,ListLength);

    struct somb_mngr_reg_serviceitem *pui32ServiceList = malloc(sizeof(struct somb_mngr_reg_serviceitem)*ListLength);
    if((NULL == pui32ServiceList))
    {
        SOMB_LOG_ERR("somb user:pid(%d) event listener deploy ,malloc service list failed",getpid());
        return SOMB_FAIL;
    }
    memset(pui32ServiceList,0,sizeof(sizeof(struct somb_mngr_reg_serviceitem)*ListLength));

    uint32_t loop = 0;
    for(;loop < ListLength;loop++)
    {
        pui32ServiceList[loop].ServiceId = ListenList[loop].ServiceId;
        pui32ServiceList[loop].ServiceType = ListenList[loop].ServiceType; 
        if(pui32ServiceList[loop].ServiceType == SOMB_SVC_TYPE_EVENT)
        {
            pui32ServiceList[loop].ServiceFlags = ListenList[loop].ListenerFlags; 
        }
        void *Priv=NULL;
        if(SOMB_SVC_TYPE_EVENT == ListenList[loop].ServiceType)
        {
            Priv = ListenList[loop].ListenerCB;
        }
        else if(SOMB_SVC_TYPE_METHOD == ListenList[loop].ServiceType)
        {
            Priv = ListenList[loop].OnAvailableCB;
        }

        if(NULL == pstSOMB_Manager_SaveService(pui32ServiceList[loop].ServiceId,pui32ServiceList[loop].ServiceType,Priv,NULL)) 
        {
            SOMB_LOG_ERR("somb user:subns(%s) pid(%d) event listener deploy ,service(%08x)",pstLocalSubNs->localexename,pstLocalSubNs->localpid,ListenList[loop].ServiceId);
        }
    }

    ret = i32SOMB_Manager_RegisterListenEvent_2_Daemon(pui32ServiceList,ListLength,true);
    if(SOMB_OK != ret)
    {
        SOMB_LOG_ERR("somb msg:pid(%d) register event listener to daemon failed",getpid());
    }

    free(pui32ServiceList);

    return ret;
}
int32_t i32SOMB_EventListener_Delete(uint32_t ServiceIdList[],uint32_t ListLength)
{
    int32_t ret;
    struct somb_mngr_reg_serviceitem *pui32ServiceList = malloc(sizeof(struct somb_mngr_reg_serviceitem)*ListLength);
    if((NULL == pui32ServiceList))
    {
        SOMB_LOG_ERR("somb user:pid(%d) event listener delete,malloc service list failed",getpid());
        return SOMB_FAIL;
    }
    memset(pui32ServiceList,0,sizeof(sizeof(struct somb_mngr_reg_serviceitem)*ListLength));

    struct somb_local_sub_ns *pstLocalSubNs = pstSOMB_GetLocalSubNs();
    if(NULL == pstLocalSubNs)
    {
        SOMB_LOG_ERR("somb user:pid(%d) event listener delete ,get local Sub ns failed",getpid());
        free(pui32ServiceList);
        return SOMB_FAIL;
    }

    SOMB_LOG_DEBUG("somb user:subns(%s) pid(%d) event listener delete ,service len=%d",pstLocalSubNs->localexename,pstLocalSubNs->localpid,ListLength);

    uint32_t loop = 0;
    for(;loop < ListLength;loop++)
    {
        pui32ServiceList[loop].ServiceId = ServiceIdList[loop];
        pui32ServiceList[loop].ServiceType = SOMB_SVC_TYPE_EVENT;
    }

    ret = i32SOMB_Manager_RegisterListenEvent_2_Daemon(pui32ServiceList,ListLength,false);
    if(SOMB_OK != ret)
    {
        SOMB_LOG_ERR("somb msg:pid(%d) delete event listener to daemon failed",getpid());
    }

    free(pui32ServiceList);

    return ret;
}

int32_t i32SOMB_Event_Trigger_To_Subns(ST_SOMB_LIB_SERVICE_LIST *Service,void *EventData,uint32_t EventDataLen, struct somb_mngr_service_subns_item *dest_subns)
{
    struct somb_local_sub_ns *pstLocalSubNs = pstSOMB_GetLocalSubNs();
    pthread_mutex_lock(&(dest_subns->pstSubNs->mutex_lock));
    uint8_t MsgSeqId = atomic_fetch_add(&(Service->pstSubNs->MsgSeqId),1);

    uint8_t header[SOMB_MESSAGE_HEADER_SIZE];
    uint32_t bodysize=0;
    if((NULL == EventData) || (0 == EventDataLen))
    {
        bodysize = 0;
        SOMB_MESSAGE_HEADER_INIT(header,pstLocalSubNs->sub_ns_id,MsgSeqId,Service->ServiceId,SOMB_MSG_TYPE_EVENT,0);
        
    }
    else
    {
        SOMB_MESSAGE_HEADER_INIT(header,pstLocalSubNs->sub_ns_id,MsgSeqId,Service->ServiceId,SOMB_MSG_TYPE_EVENT,EventDataLen);
        bodysize = EventDataLen;
    }
    int32_t ret = i32somb_send_message_raw(pstLocalSubNs,dest_subns->pstSubNs,header,EventData,bodysize);
    if(ret != SOMB_OK)
    {
        SOMB_LOG_ERR("somb msg:subns(%s) pid(%d) trigger event ServiceId(%08x) to subns(%d) failed",pstLocalSubNs->localexename,getpid(),Service->ServiceId,dest_subns->pstSubNs->sub_ns_id);
    }
    pthread_mutex_unlock(&(dest_subns->pstSubNs->mutex_lock));

    return ret;

}

int32_t i32SOMB_Event_Trigger(uint32_t ServiceId,void *EventData,uint32_t EventDataLen)
{

    int ret;
    struct somb_local_sub_ns *pstLocalSubNs = pstSOMB_GetLocalSubNs();
    if(NULL == pstLocalSubNs)
    {
        SOMB_LOG_ERR("somb msg:pid(%d) method resp sync ServiceId(%08x), get local sub ns failed",getpid(),ServiceId);
        return SOMB_FAIL;
    }

    ST_SOMB_LIB_SERVICE_LIST * pstLibServiceList = pstSOMBManagerGetServiceInfo(ServiceId);
    if(NULL == pstLibServiceList)
    {
        SOMB_LOG_ERR("somb msg:subns(%s) pid(%d) trigger event ServiceId(%08x),but get Service list failed",pstLocalSubNs->localexename,getpid(),ServiceId);
        return SOMB_FAIL;
    }


    bool bTiggerErrorFlag = false;
    atomic_fetch_add(&(pstLibServiceList->ServiceCount),1);
    //uint8_t header[SOMB_MESSAGE_HEADER_SIZE];
    struct somb_mngr_service_subns_item *item,*tmp;
    DL_FOREACH_SAFE(pstLibServiceList->listen_subns_listhead,item,tmp)
    {
        if(NULL != item->pstSubNs)
        {
            pthread_mutex_lock(&(item->pstSubNs->mutex_lock));
            uint8_t MsgSeqId = atomic_fetch_add(&(pstLibServiceList->pstSubNs->MsgSeqId),1);

            uint8_t header[SOMB_MESSAGE_HEADER_SIZE];
            uint32_t bodysize=0;
            if((NULL == EventData) || (0 == EventDataLen))
            {
                bodysize = 0;
                SOMB_MESSAGE_HEADER_INIT(header,pstLocalSubNs->sub_ns_id,MsgSeqId,ServiceId,SOMB_MSG_TYPE_EVENT,0);
                
            }
            else
            {
                SOMB_MESSAGE_HEADER_INIT(header,pstLocalSubNs->sub_ns_id,MsgSeqId,ServiceId,SOMB_MSG_TYPE_EVENT,EventDataLen);
                bodysize = EventDataLen;
            }
            ret = i32somb_send_message_raw(pstLocalSubNs,item->pstSubNs,header,EventData,bodysize);
            if(ret != SOMB_OK)
            {
                bTiggerErrorFlag = true;
                SOMB_LOG_ERR("somb msg:subns(%s) pid(%d) trigger event ServiceId(%08x) to subns(%d) failed",pstLocalSubNs->localexename,getpid(),ServiceId,item->pstSubNs->sub_ns_id);
            }
            pthread_mutex_unlock(&(item->pstSubNs->mutex_lock));
        }
        else
        {
            SOMB_LOG_ERR("somb msg:subns(%s) pid(%d) trigger event ServiceId(%08x),find NULL subns in list",pstLocalSubNs->localexename,getpid(),ServiceId);
        }
    }
    if(bTiggerErrorFlag)
    {
        atomic_fetch_add(&(pstLibServiceList->ServiceFailCount),1);
    }

    return SOMB_OK;
}
void*SOMB_Alloc(uint32_t size)
{
    void *tmp = malloc(size);
    if(tmp)
        memset(tmp,0,size);
    return tmp;
}
void SOMB_Free(void *pBuffer)
{
    free(pBuffer);
}

int32_t i32SOMB_ServiceCtrl(uint32_t ServiceId,E_SOMB_SERVICE_CTRLCMD CtrlCmd,void *CmdData)
{
    int32_t ret = 0;

    if(NULL == CmdData)
    {
        return SOMB_PARAM_ERR;
    }

    return ret;
}

int32_t i32SOMB_Service_SetAvailable(uint32_t ServiceIdList[], uint32_t ListLength, bool bAvailable)
{
    int32_t ret;

    struct somb_local_sub_ns *pstLocalSubNs = pstSOMB_GetLocalSubNs();
    if(NULL == pstLocalSubNs)
    {
        SOMB_LOG_ERR("somb user:pid(%d) change service available  status(%d) ,get local Sub ns failed",getpid(), bAvailable);
        return SOMB_FAIL;
    }

    SOMB_LOG_DEBUG("somb user:subns(%s) pid(%d) change service available ,service len=%d",pstLocalSubNs->localexename,pstLocalSubNs->localpid,ListLength);

    #define AVAILABLE_MSG_SERVICE_COUNT 256 
    uint32_t out_loop = ListLength/AVAILABLE_MSG_SERVICE_COUNT;
    uint32_t j_last  = ListLength%AVAILABLE_MSG_SERVICE_COUNT;
    if(j_last > 0)
    {
        out_loop += 1;
    }
    else
    {
        j_last = AVAILABLE_MSG_SERVICE_COUNT;
    }
        
    uint32_t i=0;
    for(; i < out_loop; i++)
    {
        somb_msg_set_service_available ServiceAvailableMsg;
        memset(&ServiceAvailableMsg, 0, sizeof(ServiceAvailableMsg));

        ServiceAvailableMsg.sub_ns_id = pstLocalSubNs->sub_ns_id;
        uint32_t loop = 0;
        uint32_t j_start= 0+ i*AVAILABLE_MSG_SERVICE_COUNT;
        uint32_t j_max = ((i+1) == out_loop)? j_last:AVAILABLE_MSG_SERVICE_COUNT;
        ServiceAvailableMsg.service_available_count = j_max;

        for(;loop < j_max; loop++)
        {
            ServiceAvailableMsg.service_available[loop].service_id= ServiceIdList[j_start];
            ServiceAvailableMsg.service_available[loop].available = bAvailable;
            j_start++;
        }

        ret = i32SOMB_Manager_ChangeServiceStatus_2_Daemon(&ServiceAvailableMsg);
        if(SOMB_OK != ret)
        {
            SOMB_LOG_ERR("somb msg:pid(%d) (ListLen=%d out_loop=%d, i=%d, j_last=%d )change service available status to daemon failed",
                         getpid(),
                         ListLength, out_loop, i, j_last);
        }

    }

    return ret;

}
int32_t i32SOMB_Service_SetAvailableWithMask(uint32_t mask, uint32_t mask_value, bool bAvailable)
{
    somb_msg_set_service_available_with_mask  maskmsg = somb_msg_set_service_available_with_mask_init_zero;

    struct somb_local_sub_ns *pstLocalSubNs = pstSOMB_GetLocalSubNs();
    if(NULL == pstLocalSubNs)
    {
        SOMB_LOG_ERR("somb user:pid(%d) change service available with mask status(%d) ,get local Sub ns failed",getpid(), bAvailable);
        return SOMB_FAIL;
    }

    maskmsg.sub_ns_id = pstLocalSubNs->sub_ns_id;
    maskmsg.mask = mask&0xFFFF0000; /* only support mask the high 16 bits*/
    maskmsg.mask_value = mask_value&0xFFFF0000;
    maskmsg.available = bAvailable;

    int32_t ret = i32SOMB_Manager_ChangeServiceStatusWithMask_2_Daemon(&maskmsg);
    if(SOMB_OK != ret)
    {
        SOMB_LOG_ERR("somb msg:pid(%d) (mask=0x%08x bAvailable=%d) change service available status to daemon failed",
                     getpid(), mask, bAvailable);
    }

    return ret;
}
